package com.ld.shieldsb.dao;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Map;

import javax.sql.DataSource;

import com.ld.shieldsb.common.core.util.StackTraceUtil;
import com.ld.shieldsb.dao.model.JoinModel;
import com.ld.shieldsb.dao.util.LogUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TransactionDao extends BasicDao {

    protected ThreadLocal<Connection> CONNECTION_THREAD_LOCAL;
    protected ThreadLocal<JoinModel> joinModelThreadLocal = new ThreadLocal<>();
    protected DataSource DATA_SOURCE;
    protected String dataSourceKey;

    public TransactionDao(String key) {
        super();
        dataSourceKey = key;
        DATA_SOURCE = DataSourceFactory.getDataSource(key);
        CONNECTION_THREAD_LOCAL = DataSourceFactory.getThreadLocalConnection(key);
        EXCEPTION_THREAD_LOCAL = DataSourceFactory.getThreadLocalException(key);
        canSave = DaoParams.getCanSave(key);
        canRead = DaoParams.getCanRead(key);
    }

    /**
     * 
     * 开始事务（建议使用TransactionManager进行事务管理）
     * 
     * @Title starTransaction
     * @throws SQLException
     *             void
     */
    @Deprecated
    public void starTransaction() throws SQLException {
        Connection con = getConnection();
        con.setAutoCommit(false);
    }

    /**
     * 判断是否开启了事务（建议使用TransactionManager进行事务管理）
     * 
     * @Title hasTransaction
     * @author 吕凯
     * @date 2019年3月22日 下午5:10:44
     * @return
     * @throws SQLException
     *             boolean
     */
    @Deprecated
    public boolean hasTransaction() throws SQLException {
        Connection con = getConnection();
        return !con.getAutoCommit(); // 非自动提交即开启了事务
    }

    /**
     * 
     * 提交事务（建议使用TransactionManager进行事务管理）
     * 
     * @Title commitTransaction
     * @throws Exception
     *             void
     */
    @Deprecated
    public void commitTransaction() throws Exception {
        Connection con = CONNECTION_THREAD_LOCAL.get();
        Exception excep = getException();
        if (excep == null) {
            if (con != null) {
                con.commit();
                con.setAutoCommit(true);
                closeConnection(con);
            } else {
                String msg = StackTraceUtil.getTrace();
                log.error("事务提交失败，连接为空！" + msg);
            }
        } else {
            log.error("事务提交失败，存在异常,进行回滚！");
            throw new Exception(excep);
        }
    }

    /**
     * 覆盖父类方法，将异常信息写到事务管理器中
     * 
     * @Title setException
     * @author 吕凯
     * @date 2019年3月29日 下午5:27:36
     * @param e
     * @see com.ld.dao.BasicDao#setException(java.lang.Exception)
     */
    @Override
    public void setException(Exception e) {
        super.setException(e);
        TransactionManager.saveException(DATA_SOURCE, e);
    }

    /**
     * 
     * 回滚事务（建议使用TransactionManager进行事务管理）
     * 
     * @Title rollbackTransaction
     * @return boolean
     */
    @Deprecated
    public boolean rollbackTransaction() {
        Connection con = CONNECTION_THREAD_LOCAL.get();
        if (con != null) {
            try {
                log.info("回滚事务");
                con.rollback();
                con.setAutoCommit(true);
                closeConnection(con);
                return true;
            } catch (Exception e) {
                log.error("事务回滚失败！", e);
            }
        } else {
            log.error("事务回滚失败，连接为空！");
        }
        return false;
    }

    private Connection getConnection() throws SQLException {
        Connection connection = CONNECTION_THREAD_LOCAL.get();
        if (connection != null && !connection.isClosed()) {
            return connection;
        } else {
            connection = TransactionManager.getCurrentThreadConnection(DATA_SOURCE);// 改为从事务管理器中获取
            CONNECTION_THREAD_LOCAL.set(connection);
            return connection;
        }
    }

    private void closeConnection(Connection con) throws SQLException {
        con.close();
        CONNECTION_THREAD_LOCAL.remove();
        EXCEPTION_THREAD_LOCAL.remove();
        TransactionManager.closeConn(DATA_SOURCE); // 事务管理器中关闭连接
    }

    protected Connection getCon() throws SQLException {
        return getConnection();
    }

    protected void closeCon(Connection con) throws SQLException {
        closeConnection(con);
    }

    // 允许查看
    public JoinModel getJoinModel() {
        JoinModel model = joinModelThreadLocal.get();
        return model;
    }

    protected JoinModel setJoinModel(JoinModel join) {
        joinModelThreadLocal.set(join);
        return join;
    }

    // 允许外部关闭
    public void clearJoin() {
        joinModelThreadLocal.remove();
    }

    public int update(String sql, Object... params) {
        try {
            if (canSave) {
                Connection connection = getCon();
                if (connection.getAutoCommit()) { // 未加事务，完后关闭连接
                    try {
                        LogUtil.daoDebug("sql: " + sql + " params: " + Arrays.asList(params));
                        return QRY_RUN.update(connection, sql, params);
                    } finally {
                        closeCon(connection);
                    }
                } else {
                    if (getException() == null) {
                        LogUtil.daoDebug("sql: " + sql + " params: " + Arrays.asList(params));
                        return QRY_RUN.update(connection, sql, params);
                    } else {
                        log.warn("检测到事务中存在异常(当前sql：" + sql + ")修改操作将不执行", getException());
                        return -1;
                    }
                }
            } else {
                LogUtil.daoDebug("canSave=false不执行保存 sql: " + sql + " params: " + Arrays.asList(params));
                return 0;
            }
        } catch (Exception e) {
            setException(e);
            log.error("修改出错,sql:" + sql, e);
            return 0;
        }
    }

    private int getTotal(int[] counts) {
        if (counts == null || counts.length == 0) {
            return 0;
        }
        int total = 0;
        for (int count : counts) {
            if (count != 0) {
                total++;
            }
        }
        return total;
    }

    public int batchUpdate(String sql, Object[][] params) {
        try {
            if (canSave) {
                Connection connection = getCon();
                if (connection.getAutoCommit()) {
                    try {
                        LogUtil.daoDebug("sql: " + sql + " params: " + Arrays.asList(params));
                        int[] counts = QRY_RUN.batch(connection, sql, params);
                        return getTotal(counts);
                    } finally {
                        closeCon(connection);
                    }
                } else {
                    if (getException() == null) {
                        LogUtil.daoDebug("sql: " + sql + " params: " + Arrays.asList(params));
                        int[] counts = QRY_RUN.batch(connection, sql, params);
                        return getTotal(counts);
                    } else {
                        log.warn("检测到事务中存在异常(当前sql：" + sql + ")修改操作将不执行", getException());
                        return -1;
                    }
                }
            } else {
                LogUtil.daoDebug("canSave=false不执行保存 sql: " + sql + " params: " + Arrays.asList(params));
                return 0;
            }

        } catch (Exception e) {
            setException(e);
            log.error("批量更新修改出错,sql:" + sql, e);
            return 0;
        }
    }

    @Override
    protected <T> void updateIndexField(T modelBean, Field field, Map<String, Field> fileMap)
            throws IllegalArgumentException, IllegalAccessException {

    }

    @Override
    protected <T> void updateIndexFieldContrast(T modelBean, T OldmodelBean, Map<String, Field> fieldMap) {

    }

    @Override
    protected <T> long getNextIdLong(Class<T> classOfT) {
        return 0;
    }

    @Override
    protected <T> long getNextSeqValue(Class<T> classOfT, String fieldName) {
        return 0;
    }

    public String getDataSourceKey() {
        return dataSourceKey;
    }

}
